﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.IO;


namespace IveelySE.Dream.Common.Transmission
{
  
    /// <summary>
    /// 客户端连接器
    /// </summary>
    internal class ClientConnection
    {
        /// <summary>
        /// 消息接收事件（委托）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="Datas"></param>
        public delegate void MessageReceive(ClientConnection sender, byte[] Datas);

        /// <summary>
        /// 远程主机关闭事件（委托）
        /// </summary>
        /// <param name="sender"></param>
        public delegate void RemoteHostClose(ClientConnection sender);

        /// <summary>
        /// 读取大小
        /// </summary>
        private int ReadBufferSize;

        /// <summary>
        /// 读取的字节内容
        /// </summary>
        private byte[] ReadBuffer;

        /// <summary>
        /// 消息接收事件
        /// </summary>
        public event MessageReceive OnMessageReceived;

        /// <summary>
        /// 远程主机关闭事件
        /// </summary>
        public event RemoteHostClose OnRemoteHostClosed;

        /// <summary>
        /// 连接的客户端
        /// </summary>
        public TcpClient Client { get; private set; }

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="client">连接的客户端</param>
        /// <param name="bufferSize">Buffer大小，默认2048b</param>
        public ClientConnection(TcpClient client, int bufferSize = 2048)
        {
            this.ReadBufferSize = bufferSize;
            ReadBuffer = new byte[this.ReadBufferSize];
            this.Client = client;
            this.Client.GetStream().BeginRead(ReadBuffer, 0, ReadBufferSize, new AsyncCallback(StreamReceiver), this.Client);
        }

        /// <summary>
        /// 流接收器
        /// </summary>
        /// <param name="asyncResult">异步</param>
        private void StreamReceiver(IAsyncResult asyncResult)
        {
            TcpClient client = null;
            int intBytesRead = 0;
            string receivedData = string.Empty;
            NetworkStream networkStream = null;
            try
            {
                client = (TcpClient)asyncResult.AsyncState;
                if (!client.Connected)
                {
                    client.Close();
                    Console.WriteLine("Close\t" + DateTime.Now.ToString() + "\t" +
                        client.GetHashCode().ToString());
                    return;
                }
                try
                {
                    networkStream = client.GetStream();
                }
                catch
                {
                    client.Close();
                    throw;
                }
                try
                {
                    lock (networkStream)
                    {
                        intBytesRead = networkStream.EndRead(asyncResult);
                    }
                }
                catch
                {
                    client.Close();
                    throw;
                }
                if (intBytesRead > 0)
                {
                    byte[] objData = new byte[intBytesRead];
                    Array.Copy(ReadBuffer, objData, intBytesRead);
                    OnMessageReceived(this, objData);
                }
                else
                {
                    OnRemoteHostClosed(this);
                    if (networkStream != null)
                    {
                        networkStream.Close();
                    }
                    client.Close();
                    return;
                }
                if (!client.Connected)
                {
                    client.Close();
                    Console.WriteLine("client close\t" + DateTime.Now.ToString() + "\t" +client.GetHashCode().ToString());
                    return;
                }
                try
                {
                    lock (networkStream)
                    {
                        networkStream.BeginRead(ReadBuffer, 0, ReadBufferSize,
                            new AsyncCallback(StreamReceiver), client);
                    }
                }
                catch
                {
                    client.Close();
                    throw;
                }
            }
            catch
            {
                client.Close();
                throw;
            }
        }
    }
}
